use super::*;
use std::ffi::OsStr;
// use std::borrow::Cow;
const ADB_SUB_SHELL: &str = "shell";

pub struct ShellCmd<'a, T: 'a + AsRef<OsStr>> {
  args: &'a [T],
  fmt: Box<dyn Fn(&str) -> String>,
}

impl<'a, T: 'a + AsRef<OsStr>> ShellCmd<'a, T> {
  pub fn new(args: &'a [T], fmt: Option<Box<dyn Fn(&str) -> String>>) -> Self {
    ShellCmd {
      args,
      fmt: fmt.unwrap_or(Box::new(|s| s.to_string())),
    }
  }
}

impl<'a, T: 'a + AsRef<OsStr>> BinaryCommand for ShellCmd<'a, T> {
  type Output = io::Result<()>;
  fn exec(&self) -> Self::Output {
    if cfg!(target_os = "windows") {
      panic!("no impl for windows!")
    } else {
      // let cmd = Command::new(ADB_BIN).arg(ADB_SUB_SHELL);

      let output = Command::new(ADB_BIN)
        .arg(ADB_SUB_SHELL)
        .args(self.args)
        .output();
      self.process_stdout::<&str>(output, None, None);
      Ok(())
    }
  }
  fn process_stdout<U: AsRef<str>>(
    &self,
    output: io::Result<Output>,
    warning_check_strs: Option<&[U]>,
    cust_err: Option<&str>,
  ) {
    process_stdout(output, self.fmt.as_ref(), warning_check_strs, cust_err);
  }
}

pub struct OutputShellCmd<'a, T: 'a + AsRef<OsStr>> {
  args: &'a [T],
}

impl<'a, T: 'a + AsRef<OsStr>> OutputShellCmd<'a, T> {
  pub fn new(args: &'a [T]) -> Self {
    OutputShellCmd {
      args,
    }
  }
}

impl<'a, T: 'a + AsRef<OsStr>> BinaryCommand for OutputShellCmd<'a, T> {
  type Output = io::Result<String>;
  fn exec(&self) -> Self::Output {
    if cfg!(target_os = "windows") {
      panic!("no impl for windows!")
    } else {
      // let cmd = Command::new(ADB_BIN).arg(ADB_SUB_SHELL);

      let output = Command::new(ADB_BIN)
        .arg(ADB_SUB_SHELL)
        .args(self.args)
        .output()?;
      String::from_utf8(output.stdout).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e.to_string()))
    }
  }
}